home *** CD-ROM | disk | FTP | other *** search
/ Languguage OS 2 / Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO / gnu / gas_251.zip / bin_251 / bfd / cache.c < prev    next >
C/C++ Source or Header  |  1994-05-03  |  7KB  |  344 lines

  1. /* BFD library -- caching of file descriptors.
  2.    Copyright 1990, 1991, 1992, 1994 Free Software Foundation, Inc.
  3.    Hacked by Steve Chamberlain of Cygnus Support (steve@cygnus.com).
  4.  
  5. This file is part of BFD, the Binary File Descriptor library.
  6.  
  7. This program is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2 of the License, or
  10. (at your option) any later version.
  11.  
  12. This program is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15. GNU General Public License for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with this program; if not, write to the Free Software
  19. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  20.  
  21. /*
  22. SECTION
  23.     File caching
  24.  
  25.     The file caching mechanism is embedded within BFD and allows
  26.     the application to open as many BFDs as it wants without
  27.     regard to the underlying operating system's file descriptor
  28.     limit (often as low as 20 open files).  The module in
  29.     <<cache.c>> maintains a least recently used list of
  30.     <<BFD_CACHE_MAX_OPEN>> files, and exports the name
  31.     <<bfd_cache_lookup>>, which runs around and makes sure that
  32.     the required BFD is open. If not, then it chooses a file to
  33.     close, closes it and opens the one wanted, returning its file
  34.     handle. 
  35.  
  36. */
  37.  
  38. #include "bfd.h"
  39. #include "sysdep.h"
  40. #include "libbfd.h"
  41.  
  42. static void insert PARAMS ((bfd *));
  43. static void snip PARAMS ((bfd *));
  44. static boolean close_one PARAMS ((void));
  45. static boolean bfd_cache_delete PARAMS ((bfd *));
  46.  
  47. /*
  48. INTERNAL_FUNCTION
  49.     BFD_CACHE_MAX_OPEN macro
  50.  
  51. DESCRIPTION
  52.     The maximum number of files which the cache will keep open at
  53.     one time.
  54.  
  55. .#define BFD_CACHE_MAX_OPEN 10
  56.  
  57. */
  58.  
  59. /* The number of BFD files we have open.  */
  60.  
  61. static int open_files;
  62.  
  63. /*
  64. INTERNAL_FUNCTION
  65.     bfd_last_cache
  66.  
  67. SYNOPSIS
  68.     extern bfd *bfd_last_cache;
  69.  
  70. DESCRIPTION
  71.     Zero, or a pointer to the topmost BFD on the chain.  This is
  72.     used by the <<bfd_cache_lookup>> macro in @file{libbfd.h} to
  73.     determine when it can avoid a function call.
  74. */
  75.  
  76. bfd *bfd_last_cache;
  77.  
  78. /*
  79.   INTERNAL_FUNCTION
  80.       bfd_cache_lookup
  81.  
  82.   DESCRIPTION
  83.      Check to see if the required BFD is the same as the last one
  84.      looked up. If so, then it can use the stream in the BFD with
  85.      impunity, since it can't have changed since the last lookup;
  86.      otherwise, it has to perform the complicated lookup function.
  87.  
  88.   .#define bfd_cache_lookup(x) \
  89.   .    ((x)==bfd_last_cache? \
  90.   .      (FILE*)(bfd_last_cache->iostream): \
  91.   .       bfd_cache_lookup_worker(x))
  92.  
  93.  
  94.  */
  95.  
  96. /* Insert a BFD into the cache.  */
  97.  
  98. static INLINE void
  99. insert (abfd)
  100.      bfd *abfd;
  101. {
  102.   if (bfd_last_cache == NULL)
  103.     {
  104.       abfd->lru_next = abfd;
  105.       abfd->lru_prev = abfd;
  106.     }
  107.   else
  108.     {
  109.       abfd->lru_next = bfd_last_cache;
  110.       abfd->lru_prev = bfd_last_cache->lru_prev;
  111.       abfd->lru_prev->lru_next = abfd;
  112.       abfd->lru_next->lru_prev = abfd;
  113.     }
  114.   bfd_last_cache = abfd;
  115. }
  116.  
  117. /* Remove a BFD from the cache.  */
  118.  
  119. static INLINE void
  120. snip (abfd)
  121.      bfd *abfd;
  122. {
  123.   abfd->lru_prev->lru_next = abfd->lru_next;
  124.   abfd->lru_next->lru_prev = abfd->lru_prev;
  125.   if (abfd == bfd_last_cache)
  126.     {
  127.       bfd_last_cache = abfd->lru_next;
  128.       if (abfd == bfd_last_cache)
  129.     bfd_last_cache = NULL;
  130.     }
  131. }
  132.  
  133. /* We need to open a new file, and the cache is full.  Find the least
  134.    recently used cacheable BFD and close it.  */
  135.  
  136. static boolean
  137. close_one ()
  138. {
  139.   register bfd *kill;
  140.  
  141.   if (bfd_last_cache == NULL)
  142.     kill = NULL;
  143.   else
  144.     {
  145.       for (kill = bfd_last_cache->lru_prev;
  146.        ! kill->cacheable;
  147.        kill = kill->lru_prev)
  148.     {
  149.       if (kill == bfd_last_cache)
  150.         {
  151.           kill = NULL;
  152.           break;
  153.         }
  154.     }
  155.     }
  156.  
  157.   if (kill == NULL)
  158.     {
  159.       /* There are no open cacheable BFD's.  */
  160.       return true;
  161.     }
  162.  
  163.   kill->where = ftell ((FILE *) kill->iostream);
  164.  
  165.   return bfd_cache_delete (kill);
  166. }
  167.  
  168. /* Close a BFD and remove it from the cache.  */
  169.  
  170. static boolean
  171. bfd_cache_delete (abfd)
  172.      bfd *abfd;
  173. {
  174.   boolean ret;
  175.  
  176.   if (fclose ((FILE *) abfd->iostream) == 0)
  177.     ret = true;
  178.   else
  179.     {
  180.       ret = false;
  181.       bfd_set_error (bfd_error_system_call);
  182.     }
  183.  
  184.   snip (abfd);
  185.  
  186.   abfd->iostream = NULL;
  187.   --open_files;
  188.  
  189.   return ret;
  190. }
  191.  
  192. /*
  193. INTERNAL_FUNCTION
  194.     bfd_cache_init
  195.  
  196. SYNOPSIS
  197.     boolean bfd_cache_init (bfd *abfd);
  198.  
  199. DESCRIPTION
  200.     Add a newly opened BFD to the cache.
  201. */
  202.  
  203. boolean
  204. bfd_cache_init (abfd)
  205.      bfd *abfd;
  206. {
  207.   BFD_ASSERT (abfd->iostream != NULL);
  208.   if (open_files >= BFD_CACHE_MAX_OPEN)
  209.     {
  210.       if (! close_one ())
  211.     return false;
  212.     }
  213.   insert (abfd);
  214.   ++open_files;
  215.   return true;
  216. }
  217.  
  218. /*
  219. INTERNAL_FUNCTION
  220.     bfd_cache_close
  221.  
  222. SYNOPSIS
  223.     boolean bfd_cache_close (bfd *abfd);
  224.  
  225. DESCRIPTION
  226.     Remove the BFD @var{abfd} from the cache. If the attached file is open,
  227.     then close it too.
  228.  
  229. RETURNS
  230.     <<false>> is returned if closing the file fails, <<true>> is
  231.     returned if all is well.
  232. */
  233.  
  234. boolean
  235. bfd_cache_close (abfd)
  236.      bfd *abfd;
  237. {
  238.   if (abfd->iostream == NULL)
  239.     return true;
  240.  
  241.   return bfd_cache_delete (abfd);
  242. }
  243.  
  244. /*
  245. INTERNAL_FUNCTION
  246.     bfd_open_file
  247.  
  248. SYNOPSIS
  249.     FILE* bfd_open_file(bfd *abfd);
  250.  
  251. DESCRIPTION
  252.     Call the OS to open a file for @var{abfd}.  Return the <<FILE *>>
  253.     (possibly <<NULL>>) that results from this operation.  Set up the
  254.     BFD so that future accesses know the file is open. If the <<FILE *>>
  255.     returned is <<NULL>>, then it won't have been put in the
  256.     cache, so it won't have to be removed from it.
  257. */
  258.  
  259. FILE *
  260. bfd_open_file (abfd)
  261.      bfd *abfd;
  262. {
  263.   abfd->cacheable = true;    /* Allow it to be closed later. */
  264.  
  265.   if (open_files >= BFD_CACHE_MAX_OPEN)
  266.     {
  267.       if (! close_one ())
  268.     return NULL;
  269.     }
  270.  
  271.   switch (abfd->direction)
  272.     {
  273.     case read_direction:
  274.     case no_direction:
  275.       abfd->iostream = (char *) fopen (abfd->filename, FOPEN_RB);
  276.       break;
  277.     case both_direction:
  278.     case write_direction:
  279.       if (abfd->opened_once == true)
  280.     {
  281.       abfd->iostream = (char *) fopen (abfd->filename, FOPEN_RUB);
  282.       if (abfd->iostream == NULL)
  283.         abfd->iostream = (char *) fopen (abfd->filename, FOPEN_WUB);
  284.     }
  285.       else
  286.     {
  287.       /*open for creat */
  288.       abfd->iostream = (char *) fopen (abfd->filename, FOPEN_WB);
  289.       abfd->opened_once = true;
  290.     }
  291.       break;
  292.     }
  293.  
  294.   if (abfd->iostream != NULL)
  295.     {
  296.       if (! bfd_cache_init (abfd))
  297.     return NULL;
  298.     }
  299.  
  300.   return (FILE *) abfd->iostream;
  301. }
  302.  
  303. /*
  304. INTERNAL_FUNCTION
  305.     bfd_cache_lookup_worker
  306.  
  307. SYNOPSIS
  308.     FILE *bfd_cache_lookup_worker(bfd *abfd);
  309.  
  310. DESCRIPTION
  311.     Called when the macro <<bfd_cache_lookup>> fails to find a
  312.     quick answer.  Find a file descriptor for @var{abfd}.  If
  313.     necessary, it open it.  If there are already more than
  314.     <<BFD_CACHE_MAX_OPEN>> files open, it tries to close one first, to
  315.     avoid running out of file descriptors.  
  316. */
  317.  
  318. FILE *
  319. bfd_cache_lookup_worker (abfd)
  320.      bfd *abfd;
  321. {
  322.   if (abfd->my_archive) 
  323.     abfd = abfd->my_archive;
  324.  
  325.   if (abfd->iostream != NULL)
  326.     {
  327.       /* Move the file to the start of the cache.  */
  328.       if (abfd != bfd_last_cache)
  329.     {
  330.       snip (abfd);
  331.       insert (abfd);
  332.     }
  333.     }
  334.   else
  335.     {
  336.       if (bfd_open_file (abfd) == NULL)
  337.     return NULL;
  338.       if (fseek ((FILE *) abfd->iostream, abfd->where, SEEK_SET) != 0)
  339.     return NULL;
  340.     }
  341.  
  342.   return (FILE *) abfd->iostream;
  343. }
  344.